﻿' Copyright (C) 2015 HTTPBuilder
'
' This program is free software: you can redistribute it and/or modify it under the +terms 
' of the GNU General Public License as published by the Free Software Foundation, either 
' version 3 of the License, or (at your option) any later version.

' This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
' without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
' See the GNU General Public License for more details.

' You should have received a copy of the GNU General Public License along with this program.
' If not, see http://www.gnu.org/licenses/. 

Imports System.Net
Imports System.Web
Imports System.Text
Imports System.IO

Namespace Engine
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Friend NotInheritable Class HttpExecuter

#Region "Member variables"
        Private _excutionTime As TimeSpan = New TimeSpan(0)
        Private _cookieContainer As CookieContainer = New CookieContainer

        Private Shared _taskNo As Integer = 0
#End Region

#Region "Public properties"
        Public ReadOnly Property ExecutionTime As TimeSpan
            Get
                Return _excutionTime
            End Get
        End Property
        Public Property AllowRedirect As Boolean = True
        Public Property SetContentLengthHeader As Boolean = True

        Private Shared ReadOnly Property TaskNo As Integer
            Get
                _taskNo += 1
                Return _taskNo
            End Get
        End Property
#End Region

        Private Sub ProcessResponseStream(contentType As String, ByRef job As ExecutionJob, ByRef responseStream As Stream)
            If responseStream IsNot Nothing Then
                If contentType = "image/png" Then
                    Dim img As Image = Image.FromStream(responseStream)
                    job.ResponseData = img
                    job.ResponseDataType = ContentTypeEnum.Image
                Else
                    Using responseReader As StreamReader = New StreamReader(responseStream)
                        job.ResponseData = responseReader.ReadToEnd
                        job.ResponseDataType = ContentTypeEnum.Text
                    End Using
                End If
            End If
        End Sub

#Region "Public methods"
        ''' <summary>
        ''' 
        ''' </summary>
        ''' <param name="url"></param>
        ''' <param name="method"></param>
        ''' <param name="body"></param>
        ''' <param name="headers"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Run(url As String, method As String, body As String, headers As HeaderCollection) As ExecutionJob
            Dim job As ExecutionJob = New ExecutionJob() With {.Method = method, .Url = url}
            job.TaskNo = HttpExecuter.TaskNo

            Dim request As HttpWebRequest = HttpWebRequest.Create(New Uri(url))
            request.Method = method
            request.CookieContainer = _cookieContainer
            request.AllowAutoRedirect = Me.AllowRedirect
            If Me.SetContentLengthHeader AndAlso String.Compare(method, "GET", True) <> 0 Then
                headers("Content-Length") = body.Length
            End If
            headers.SetHeaders(request)

            Dim start As DateTime = DateTime.Now

            ' build request
            If Not String.IsNullOrEmpty(body) Then
                Try
                    Dim requestStream As Stream = request.GetRequestStream()

                    Using requestWriter As StreamWriter = New StreamWriter(requestStream)
                        requestWriter.Write(body)
                    End Using
                Catch ex As Exception
                    job.Status = HttpStatusCode.ExpectationFailed
                    job.StatusDescription = ex.Message
                    job.IsError = True
                    job.Exception = ex
                    'Throw ex
                End Try
            End If

            ' get response
            Try
                Dim response As HttpWebResponse = request.GetResponse()
                job.Status = response.StatusCode
                job.StatusDescription = response.StatusDescription
                job.ResponseHeaders = response.Headers
                job.ResponseCookies = response.Cookies

                ' process response
                ProcessResponseStream(response.ContentType.ToLower, job, response.GetResponseStream)
            Catch ex As WebException
                ' handled by web server
                job.Status = CType(ex.Response, HttpWebResponse).StatusCode
                job.StatusDescription = CType(ex.Response, HttpWebResponse).StatusDescription ' ex.ToString
                job.Exception = ex
                job.IsError = True
                job.ResponseHeaders = ex.Response.Headers

                If ex.Response.ContentLength > 0 Then
                    'Dim responseStream As Stream = ex.Response.GetResponseStream
                    ProcessResponseStream(ex.Response.ContentType.ToLower, job, ex.Response.GetResponseStream)
                    'If responseStream IsNot Nothing Then
                    '    Using responseReader As StreamReader = New StreamReader(responseStream)
                    '        job.ResponseBody = responseReader.ReadToEnd
                    '    End Using
                    'End If
                End If
            Catch ex As Exception
                ' unhandled by any
                job.Status = HttpStatusCode.ExpectationFailed
                job.IsError = True
                job.StatusDescription = ex.Message
                job.Exception = ex
            Finally
                job.RequestHeaders = request.Headers
            End Try

            _excutionTime = (DateTime.Now - start)
            job.Time = _excutionTime.Milliseconds
            Return job
        End Function
#End Region
    End Class
End Namespace
